package eteam.aps.systemservice.bll;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import eteam.aps.common.QueryResult;
import eteam.aps.common.enumeration.SortEnum;
import eteam.aps.common.exceptions.BusinessException;
import eteam.aps.common.helper.Helper;
import eteam.aps.common.models.PatternConstant;
import eteam.aps.systeminterface.model.dto.FlowUserDto;
import eteam.aps.systeminterface.model.dto.UserDto;
import eteam.aps.systeminterface.model.dto.VerifyTokenDto;
import eteam.aps.systeminterface.model.entity.EmpEntity;
import eteam.aps.systeminterface.model.entity.OnlineUserEntity;
import eteam.aps.systeminterface.model.entity.UserEntity;
import eteam.aps.systeminterface.model.enums.PersonTypeEnum;
import eteam.aps.systeminterface.model.enums.StateEnum;
import eteam.aps.systeminterface.model.reqparam.FindPwdParam;
import eteam.aps.systeminterface.model.reqparam.QueryOnlineUserParam;
import eteam.aps.systeminterface.model.reqparam.QueryUserParam;
import eteam.aps.systemservice.dal.*;
import eteam.aps.systemservice.model.mapper.IUserMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import java.util.List;
import java.util.Objects;

/**
 * 用户相关业务
 */
@Service
public class UserBll {
    @Autowired
    private UserDal userDal;
    @Autowired
    private OnlineUserDal onlineUserDal;
    @Autowired
    private ParamDal paramDal;
    @Autowired
    private EmpDal empDal;
    @Autowired
    private MailDal mailDal;

    /**
     * 分页查询用户列表
     *
     * @param queryParam
     * @return
     */
    public QueryResult<UserEntity> queryUserPageList(QueryUserParam queryParam) throws Exception {
        IPage<UserEntity> page = new Page<UserEntity>(queryParam.getPageIndex(), queryParam.getPageSize());
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<UserEntity>();
        wrapper.eq("t1.FGroupOrgId", queryParam.getOrgid());
        if (queryParam.getState() > StateEnum.Delete.getValue()) {
            wrapper.eq("t1.State", queryParam.getState());
        } else {
            wrapper.ne("t1.State", StateEnum.Delete.getValue());
        }
        if (StringUtils.isNotBlank(queryParam.getKeyword())) {
            wrapper.and(i -> i.like("t1.FUserName", queryParam.getKeyword()).or().like("t1.FFullName", queryParam.getKeyword()));
        }
        if (StringUtils.isNotBlank(queryParam.getSortFields()) && queryParam.getSortOrder().equals(SortEnum.Asc)) {
            wrapper.orderByAsc("t1." + queryParam.getSortFields());
        } else if (StringUtils.isNotBlank(queryParam.getSortFields()) && queryParam.getSortOrder().equals(SortEnum.Desc)) {
            wrapper.orderByDesc("t1." + queryParam.getSortFields());
        } else {
            wrapper.orderByAsc("t1.FUserName");
        }
        page = userDal.queryUserPageList(page, wrapper);
        QueryResult<UserEntity> result = new QueryResult<UserEntity>(Math.toIntExact(page.getTotal()), page.getRecords());
        return result;
    }

    /**
     * 创建用户
     *
     * @param userDto: 请求参数
     * @throws Exception
     */
    public void createUser(VerifyTokenDto tokenDto, UserDto userDto) throws Exception {
        int one = paramDal.getOne();
        if (one != 0) {
            if (Helper.isNotPattern(userDto.getFpassword(), PatternConstant.PASSWORD)) {
                throw new BusinessException("密码必须由8-12位大小写字母、特殊字符和数字组成！");
            }
        }
        UserEntity userEntity = IUserMapper.INSTANCE.toEntity(userDto);
        userEntity.setFuserid(Helper.GetId());
        userEntity.setFpersontype(PersonTypeEnum.User.getValue());
        userEntity.setFpersonid(userDto.getFpersonid());
        userEntity.setFcreator(tokenDto.getFuserid());
        userEntity.setFcreatorname(tokenDto.getFfullname());
        userEntity.setFcreatetime(DateUtil.date());
        userEntity.setFtimestamp(DateUtil.date());
        int count = userDal.insertData(userEntity);
        if (count < 1) {
            throw new BusinessException("创建用户失败");
        }
    }

    /**
     * 更新用户
     *
     * @param userDto: 请求参数
     * @throws Exception
     */
    public void updateUser(VerifyTokenDto tokenDto, UserDto userDto) throws Exception {
        UserEntity userEntity = getUserEntityById(userDto.getFuserid());
        if (userEntity.getFusername().equals("admin")) {
            throw new BusinessException("内置账号，不允许修改");
        }
        //UserEntity userEntity = IUserMapper.INSTANCE.toEntity(userDto);
        userEntity.setFusername(userDto.getFusername());
        userEntity.setFfullname(userDto.getFfullname());
        userEntity.setFpersonid(userDto.getFpersonid());
        userEntity.setState(userDto.getState());
        userEntity.setFlastmodifier(tokenDto.getFuserid());
        userEntity.setFlastmodifiername(tokenDto.getFfullname());
        userEntity.setFlastmodifytime(DateUtil.date());
        int count = userDal.updateData(userEntity);
        if (count < 1) {
            throw new BusinessException("更新用户失败");
        }
    }

    /**
     * 删除用户
     *
     * @param userId: 用户ID
     * @throws Exception
     */
    public void deleteUser(String userId) throws Exception {
        UserEntity retObj = getUserEntityById(userId);
        if (retObj.getFusername().equals("admin")) {
            throw new BusinessException("内置账号，不允许删除");
        }
        UserEntity tmpObj = new UserEntity();
        tmpObj.setFuserid(userId);
        tmpObj.setFusername(StrUtil.format("{}_{}", retObj.getFusername(), System.currentTimeMillis()));
        tmpObj.setState(StateEnum.Delete.getValue());
        int count = userDal.updateData(tmpObj);
        if (count < 1) {
            throw new BusinessException("删除用户失败");
        }
    }

    /**
     * 改变用户状态
     *
     * @param userId:    用户ID
     * @param stateEnum: 状态
     * @throws Exception
     */
    public void changeState(String userId, StateEnum stateEnum) throws Exception {
        UserEntity tmpObj = new UserEntity();
        tmpObj.setFuserid(userId);
        tmpObj.setState(stateEnum.getValue());
        int count = userDal.updateData(tmpObj);
        if (count < 1) {
            throw new BusinessException("改变用户状态失败");
        }
    }

    /**
     * 分页查询在线用户
     *
     * @param queryParam
     * @return
     */
    public QueryResult<OnlineUserEntity> queryOnlineUserPageList(QueryOnlineUserParam queryParam) throws Exception {
        IPage<OnlineUserEntity> page = new Page<OnlineUserEntity>(queryParam.getPageIndex(), queryParam.getPageSize());
        QueryWrapper<OnlineUserEntity> wrapper = new QueryWrapper<OnlineUserEntity>();
        if (StringUtils.isNotBlank(queryParam.getKeyword())) {
            wrapper.and(i -> i.like("t2.FUserName", queryParam.getKeyword()).or().like("t2.FFullName", queryParam.getKeyword()));
        }

        if (StringUtils.isNotBlank(queryParam.getSortFields()) && queryParam.getSortOrder().equals(SortEnum.Asc)) {
            wrapper.orderByAsc(queryParam.getSortFields());
        } else if (StringUtils.isNotBlank(queryParam.getSortFields()) && queryParam.getSortOrder().equals(SortEnum.Desc)) {
            wrapper.orderByDesc(queryParam.getSortFields());
        } else {
            wrapper.orderByDesc("FLoginTime");
        }
        page = onlineUserDal.selectOnlineUserPage(page, wrapper);
        QueryResult<OnlineUserEntity> result = new QueryResult<OnlineUserEntity>(Math.toIntExact(page.getTotal()), page.getRecords());
        return result;
    }

    /**
     * 删除在线用户
     *
     * @param tokenId: tokenId
     * @throws Exception
     */
    public void deleteOnlineUser(String tokenId) throws Exception {
        int count = onlineUserDal.deleteTokenById(tokenId);
        if (count < 1) {
            throw new BusinessException("删除Token失败");
        }
    }

    /**
     * 批量删除在线用户
     *
     * @param tokenIds: tokenId集合
     * @throws Exception
     */
    public void deleteOnlineUser(List<String> tokenIds) throws Exception {
        int count = onlineUserDal.deleteTokenByIds(tokenIds);
        if (count < 1) {
            throw new BusinessException("批量删除Token失败");
        }
    }

    /**
     * 重置密码
     *
     * @param userId: 用户ID
     * @param pwd:    新密码
     * @throws Exception
     */
    public void resetUserPwd(String userId, String pwd) throws Exception {
        int one = paramDal.getOne();
        if (one != 0) {
            if (Helper.isNotPattern(pwd, PatternConstant.PASSWORD)) {
                throw new BusinessException("密码必须由8-12位大小写字母、特殊字符和数字组成！");
            }
        }
        UserEntity tmpObj = new UserEntity();
        tmpObj.setFuserid(userId);
        tmpObj.setFpassword(pwd);
        int count = userDal.updateData(tmpObj);
        if (count < 1) {
            throw new BusinessException("重置密码失败");
        }
    }

    /**
     * 修改密码
     *
     * @param userId: 用户ID
     * @param oldpwd: 旧密码
     * @param newpwd: 新密码
     * @throws Exception
     */
    public void modifyUserPwd(String userId, String oldpwd, String newpwd) throws Exception {
        if (oldpwd.equals(newpwd)) {
            throw new BusinessException("新密码不能与原密码一致");
        }
        int one = paramDal.getOne();
        if (one != 0) {
            if (Helper.isNotPattern(oldpwd, PatternConstant.PASSWORD)) {
                throw new BusinessException("密码必须由8-12位大小写字母、特殊字符和数字组成！");
            }
        }
        UserEntity tmpObj = getUserEntityById(userId);
        if (!tmpObj.getFpassword().equals(oldpwd)) {
            throw new BusinessException("用户原密码不正确");
        }
        tmpObj = new UserEntity();
        tmpObj.setFuserid(userId);
        tmpObj.setFpassword(newpwd);
        int count = userDal.updateData(tmpObj);
        if (count < 1) {
            throw new BusinessException("修改密码失败");
        }
    }

    /**
     * 判断用户是否存在
     *
     * @param userId: 用户ID
     * @return
     */
    public Boolean userExist(String userId) {
        UserEntity user = userDal.getUserById(userId);
        return !Helper.checkObjAllFieldsIsNull(user);
    }

    /**
     * 根据角色名称下，所有用户名称
     *
     * @param orgId:    机构ID
     * @param roleName: 角色名称
     * @return: 用户名列表
     */
    public List<String> getUserNameByRoleName(String orgId, String roleName) {
        return userDal.getUserNameByRoleName(orgId, roleName);
    }

    /**
     * 根据角色名称下，所有用户信息
     *
     * @param orgId:    机构ID
     * @param roleName: 角色名称
     * @return: 用户信息列表
     */
    public List<FlowUserDto> getUserListByRoleName(String orgId, String roleName) {
        return userDal.getUserListByRoleName(orgId, roleName);
    }

    /**
     * 获取机构Id获取用户ID列表
     *
     * @param orgId: 机构ID
     * @return: 用户ID列表
     */
    public List<String> getUserIdByOrgId(String orgId) {
        return userDal.getUserIdByOrgId(orgId);
    }

    /**
     * 获取用户的机构Id
     *
     * @param userName: 用户名
     * @return: 机构ID
     */
    public String getOrgIdByUserName(String userName) {
        UserEntity tmpUser = userDal.getUserByUsername(userName);
        if (Helper.checkObjAllFieldsIsNull(tmpUser)) {
            return "";
        } else {
            return tmpUser.getFgrouporgid();
        }
    }

    /**
     * 通过用户登录名、姓名、拼音码查找用户信息
     *
     * @param keyWord: 检索关键字【登录名、姓名、拼音码】
     * @return: 用户信息列表
     */
    public List<FlowUserDto> getUserListByKeyWord(String keyWord) {
        return userDal.getUserListByKeyWord(keyWord);
    }

    /**
     * 通过用户Id获取用户信息
     *
     * @param userId: 用户ID
     * @param orgId:  机构ID
     * @return: 用户信息
     */
    public FlowUserDto getUserByIdAndOrgId(String userId, String orgId) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("FUserId", userId);
        if (StringUtils.isNotBlank(orgId)) {
            wrapper.eq("FGroupOrgId", orgId);
        }
        UserEntity tmpUser = userDal.getUserByWrapper(wrapper);
        if (Objects.isNull(tmpUser)) {
            return null;
        } else {
            FlowUserDto retObj = new FlowUserDto();
            retObj.setUserid(tmpUser.getFuserid());
            retObj.setUsername(tmpUser.getFfullname());
            retObj.setJobname("");
            retObj.setPinyincode("");
            return retObj;
        }
    }

    /**
     * 根据机构Id获取所有用户信息
     *
     * @param orgId: 机构ID
     * @return: 用户信息列表
     */
    public List<FlowUserDto> getUserListByOrgId(String orgId) {
        return userDal.getUserListByOrgId(orgId);
    }

    //region 私有方法

    /**
     * 返回用户实体
     *
     * @param userId
     * @return
     */
    private UserEntity getUserEntityById(String userId) throws Exception {
        UserEntity retObj = userDal.getUserById(userId);
        if (Objects.isNull(retObj)) {
            throw new BusinessException("用户不存在");
        }
        if (retObj.getState().equals(StateEnum.Delete.getValue())) {
            throw new BusinessException("用户不存在");
        }
        return retObj;
    }

    /**
     * 找回密码
     *
     * @param findPwdParam 校验参数
     * @return 邮箱
     */
    public String findSelPwd(FindPwdParam findPwdParam) throws MessagingException {
        UserEntity userEntity = userDal.findSelPwd(findPwdParam.getUsername());
        if (Objects.isNull(userEntity)) {
            throw new BusinessException("用户不存在！");
        }
        if (userEntity.getState().equals(StateEnum.Delete.getValue())) {
            throw new BusinessException("用户不存在！");
        }
        EmpEntity empEntity = empDal.selectOne(userEntity.getFpersonid());
        if (Objects.isNull(empEntity)) {
            throw new BusinessException("不存在员工信息！");
        }
        if (empEntity.getState().equals(StateEnum.Delete.getValue())) {
            throw new BusinessException("不存在员工信息！");
        }
        if (!empEntity.getFemail().equalsIgnoreCase(findPwdParam.getEmail())) {
            throw new BusinessException("邮箱不正确！");
        }
        if (Helper.isEmpty(empEntity.getFemail())) {
            throw new BusinessException("邮箱不存在！");
        }
        // 发送邮箱
        mailDal.sendSimple(empEntity.getFemail(), String.format("%s,%s,%s",
                userEntity.getFfullname(), userEntity.getFusername(), userEntity.getFpassword()));
        return empEntity.getFemail();
    }
    //endregion
}
